/**
 * WebSocket管理类
 * 功能：
 * 1. 支持普通字符串、16进制字符串、16进制数组的发送
 * 2. 自动处理接收数据的类型转换
 * 3. 支持断线重连
 * 4. 支持心跳检测
 * 5. 兼容APP和H5环境
 */
class WebSocketManager {
  constructor(options = {}) {
    // 默认配置
    const defaultOptions = {
      url: '', // WebSocket服务器地址
      heartTime: 30000, // 心跳间隔(ms)
      reconnectLimit: 5, // 最大重连次数
      reconnectInterval: 5000, // 重连间隔(ms)
      binaryType: 'arraybuffer', // 二进制类型 arraybuffer/blob
      autoReconnect: true, // 是否自动重连
      onOpen: null, // 连接成功回调
      onClose: null, // 连接关闭回调
      onMessage: null, // 消息接收回调
      onError: null, // 错误回调
      onReconnect: null // 重连回调
    };

    this.options = { ...defaultOptions, ...options };
    this.ws = null; // WebSocket实例
    this.reconnectCount = 0; // 当前重连次数
    this.heartTimer = null; // 心跳定时器
    this.reconnectTimer = null; // 重连定时器
    this.isManualClose = false; // 是否手动关闭
    this.lockReconnect = false; // 避免重复重连
  }

  /**
   * 创建WebSocket连接
   */
  connect() {
    if (this.ws) {
      this.close();
    }

    // 检查URL
    if (!this.options.url) {
      console.error('WebSocket URL is required');
      return;
    }

    // 重置状态
    this.isManualClose = false;
    this.reconnectCount = 0;

    try {
      // #ifdef APP-PLUS
      // APP端使用plus的WebSocket
      this.ws = new plus.net.WebSocket(this.options.url);
      // #endif
      
      // #ifndef APP-PLUS
      // H5和小程序端使用原生WebSocket
      this.ws = new WebSocket(this.options.url);
      // #endif

      // 设置二进制类型
      if (this.ws.binaryType !== undefined) {
        this.ws.binaryType = this.options.binaryType;
      }

      // 绑定事件
      this.ws.onopen = (e) => this._onOpen(e);
      this.ws.onclose = (e) => this._onClose(e);
      this.ws.onerror = (e) => this._onError(e);
      this.ws.onmessage = (e) => this._onMessage(e);
    } catch (e) {
      console.error('WebSocket connect error:', e);
      this._reconnect();
    }
  }

  /**
   * 关闭WebSocket连接
   */
  close() {
    if (this.ws) {
      this.isManualClose = true;
      this._clearHeartBeat();
      this._clearReconnect();
      this.ws.close();
      this.ws = null;
    }
  }

  /**
   * 发送数据
   * @param {string|ArrayBuffer|Uint8Array} data - 要发送的数据
   * @param {string} [type='string'] - 数据类型: 'string'|'hex'|'arraybuffer'
   */
  send(data, type = 'string') {
    if (!this.ws || this.ws.readyState !== this.ws.OPEN) {
      console.warn('WebSocket is not connected');
      return false;
    }

    try {
      let sendData;
      switch (type) {
        case 'hex': // 16进制字符串
          sendData = this._hexStringToArrayBuffer(data);
          break;
        case 'arraybuffer': // 16进制数组
          sendData = data;
          if (!(data instanceof ArrayBuffer) && !(data instanceof Uint8Array)) {
            throw new Error('Invalid ArrayBuffer data');
          }
          break;
        case 'string': // 普通字符串
        default:
          sendData = data;
          break;
      }

      this.ws.send(sendData);
      return true;
    } catch (e) {
      console.error('WebSocket send error:', e);
      return false;
    }
  }

  /**
   * 连接成功回调
   */
  _onOpen(e) {
    console.log('WebSocket connected');
    this.reconnectCount = 0;
    this._clearReconnect();
    this._startHeartBeat();
    
    if (typeof this.options.onOpen === 'function') {
      this.options.onOpen(e);
    }
  }

  /**
   * 连接关闭回调
   */
  _onClose(e) {
    console.log('WebSocket closed:', e);
    this._clearHeartBeat();
    
    if (typeof this.options.onClose === 'function') {
      this.options.onClose(e);
    }
    
    // 非手动关闭且需要重连
    if (!this.isManualClose && this.options.autoReconnect) {
      this._reconnect();
    }
  }

  /**
   * 错误回调
   */
  _onError(e) {
    console.error('WebSocket error:', e);
    
    if (typeof this.options.onError === 'function') {
      this.options.onError(e);
    }
    
    // 错误时也尝试重连
    if (!this.isManualClose && this.options.autoReconnect) {
      this._reconnect();
    }
  }

  /**
   * 消息接收回调
   */
  _onMessage(e) {
    // 重置心跳
    this._resetHeartBeat();
    
    let data = e.data;
    let type = 'string';
    
    // 处理二进制数据
    if (data instanceof ArrayBuffer || data instanceof Uint8Array) {
      // 转换为16进制字符串
      data = this._arrayBufferToHexString(data);
      type = 'hex';
    } else if (typeof data === 'string') {
      // 检查是否是16进制字符串
      if (/^[0-9a-fA-F]+$/.test(data)) {
        type = 'hex';
      }
    }
    
    if (typeof this.options.onMessage === 'function') {
      this.options.onMessage(data, type);
    }
  }

  /**
   * 开始重连
   */
  _reconnect() {
    if (this.lockReconnect || this.isManualClose) return;
    
    this._clearReconnect();
    
    if (this.reconnectCount >= this.options.reconnectLimit) {
      console.error(`WebSocket reconnect limit (${this.options.reconnectLimit}) reached`);
      return;
    }
    
    this.lockReconnect = true;
    this.reconnectCount++;
    
    if (typeof this.options.onReconnect === 'function') {
      this.options.onReconnect(this.reconnectCount);
    }
    
    console.log(`WebSocket reconnecting... (${this.reconnectCount}/${this.options.reconnectLimit})`);
    
    this.reconnectTimer = setTimeout(() => {
      this.connect();
      this.lockReconnect = false;
    }, this.options.reconnectInterval);
  }

  /**
   * 开始心跳检测
   */
  _startHeartBeat() {
    if (!this.options.heartTime || this.options.heartTime <= 0) return;
    
    this._resetHeartBeat();
  }

  /**
   * 重置心跳检测
   */
  _resetHeartBeat() {
    this._clearHeartBeat();
    
    this.heartTimer = setTimeout(() => {
      // 发送心跳消息，这里可以根据服务器要求自定义
      if (this.ws && this.ws.readyState === this.ws.OPEN) {
        this.send('ping', 'string');
      }
      
      // 检查连接状态
      this.heartTimer = setTimeout(() => {
        if (this.ws && this.ws.readyState !== this.ws.CLOSED) {
          // 心跳无响应，关闭连接触发重连
          this.ws.close();
        }
      }, this.options.heartTime / 2);
    }, this.options.heartTime);
  }

  /**
   * 清除心跳定时器
   */
  _clearHeartBeat() {
    if (this.heartTimer) {
      clearTimeout(this.heartTimer);
      this.heartTimer = null;
    }
  }

  /**
   * 清除重连定时器
   */
  _clearReconnect() {
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }
  }

  /**
   * 16进制字符串转ArrayBuffer
   * @param {string} hexString - 16进制字符串
   * @returns {ArrayBuffer}
   */
  _hexStringToArrayBuffer(hexString) {
    // 移除可能存在的空格和0x前缀
    hexString = hexString.replace(/\s/g, '').replace(/^0x/, '');
    
    // 确保长度为偶数
    if (hexString.length % 2 !== 0) {
      hexString = '0' + hexString;
    }
    
    const length = hexString.length / 2;
    const buffer = new ArrayBuffer(length);
    const view = new Uint8Array(buffer);
    
    for (let i = 0; i < length; i++) {
      const byte = parseInt(hexString.substr(i * 2, 2), 16);
      view[i] = byte;
    }
    
    return buffer;
  }

  /**
   * ArrayBuffer转16进制字符串
   * @param {ArrayBuffer|Uint8Array} buffer - 二进制数据
   * @returns {string} 16进制字符串
   */
  _arrayBufferToHexString(buffer) {
    if (buffer instanceof Uint8Array) {
      return Array.from(buffer)
        .map(byte => byte.toString(16).padStart(2, '0'))
        .join('');
    }
    
    const view = new Uint8Array(buffer);
    let hexString = '';
    
    for (let i = 0; i < view.length; i++) {
      const hex = view[i].toString(16).padStart(2, '0');
      hexString += hex;
    }
    
    return hexString;
  }
}

export default WebSocketManager;